import abc
from typing import Generic, Iterable, Optional, TypeVar, Union

from .tagkey import TagKey

AnyValue = TypeVar("AnyValue")
AnyTagKey = TypeVar("AnyTagKey", bound=TagKey)
AnyTagVal = TypeVar("AnyTagVal")
AnyTagQuery = TypeVar("AnyTagQuery")
Queries = Union[dict[AnyTagKey, AnyTagQuery], Iterable[tuple[AnyTagKey, AnyTagQuery]]]
Tags = Union[dict[AnyTagKey, AnyTagVal], Iterable[tuple[AnyTagKey, AnyTagVal]]]


class Registry(Generic[AnyTagKey, AnyTagVal, AnyValue], abc.ABC):
    @abc.abstractmethod
    def match(self, queries: Queries) -> tuple[AnyValue, ...]:
        pass

    def match_one_or_raise(self, queries: Queries) -> AnyValue:
        matched = self.match(queries)
        if not matched:
            raise KeyError(f"Failed to match queries={queries}")
        return matched[-1]

    def match_one_or_none(self, queries: Queries) -> Optional[AnyValue]:
        matched = self.match(queries)
        if not matched:
            return None
        return matched[-1]


class MutableRegistry(Registry[AnyTagKey, AnyTagVal, AnyValue], abc.ABC):
    @abc.abstractmethod
    def register(self, tags: Tags, value: AnyValue):
        pass
